
#include <BStyle>
#include <BPainter>
#include <BScrollBar>
#include <BMouseEvent>
#include <BSizePolicy>
#include <BVBoxLayout>
#include <BHBoxLayout>

#include "member_BScrollWidget.h"
#include "member_BScrollArea.h"
#include "member_BLayout.h"

using namespace BWE;

#define member					(*(member_BScrollWidget*)_ptr)
#define member_allocate()		_ptr = new member_BScrollWidget(this)
#define member_release()		delete (member_BScrollWidget*)_ptr

BScrollWidget::BScrollWidget(BWidget* parent) : BScrollArea(parent)
{
	member_allocate();
}
BScrollWidget::BScrollWidget(const BString& title, BWidget* parent) : BScrollArea(title, parent)
{
	member_allocate();
}
BScrollWidget::BScrollWidget(Orientation orientation, BWidget* parent) : BScrollArea(parent)
{
	member_allocate();
	this->setOrientation(orientation);
}
BScrollWidget::~BScrollWidget()
{
	member_release();
}

void BScrollWidget::setOrientation(Orientation orientation)
{
	if (member.orientation != orientation)
	{
		member.orientation = orientation;
		BLayout* layout = 0;
		if (member.orientation == Orientation_Vertical)
		{
			BVBoxLayout* vlayout = new BVBoxLayout();
			for (int i = 0; i < member.layout->count(); i++)
				vlayout->addWidget(member.layout->widget(i));
			layout = vlayout;
		}
		if (member.orientation == Orientation_Horizontal)
		{
			BHBoxLayout* hlayout = new BHBoxLayout();
			for (int i = 0; i < member.layout->count(); i++)
				hlayout->addWidget(member.layout->widget(i));
			layout = hlayout;
		}
		if (member.layout)
			this->removeLayout(member.layout);
		member.layout = layout;
		if (member.layout)
			member.layout->setName("area");
		this->addLayout(layout);
		this->emit(Signal_OrientationChanged, orientation);
	}
}
Orientation BScrollWidget::orientation() const
{
	return member.orientation;
}

bool BScrollWidget::addWidget(BWidget* widget, float stretch)
{
	if (!widget)
		return false;
	if (!member.layout->contain(widget))
	{
		this->addChild(widget);
		if (BVBoxLayout* vlayout = member.layout.as<BVBoxLayout>())
		{
			vlayout->addWidget(widget, stretch);
			widget->setFloating(false);
			this->emit(Signal_ItemInserted, widget);
			return true;
		}
		if (BHBoxLayout* hlayout = member.layout.as<BHBoxLayout>())
		{
			hlayout->addWidget(widget, stretch);
			widget->setFloating(false);
			this->emit(Signal_ItemInserted, widget);
			return true;
		}
	}
	return false;
}
bool BScrollWidget::insertWidget(int index, BWidget* widget, float stretch)
{
	if (member.layout->contain(widget))
		return false;
	if (BVBoxLayout* vlayout = member.layout.as<BVBoxLayout>())
	{
		if (vlayout->insertWidget(index, widget, stretch))
		{
			this->addChild(widget);
			widget->setFloating(false);
			this->emit(Signal_ItemInserted, widget);
			return true;
		}
		return false;
	}
	if (BHBoxLayout* hlayout = member.layout.as<BHBoxLayout>())
	{
		if (hlayout->insertWidget(index, widget, stretch))
		{
			this->addChild(widget);
			widget->setFloating(false);
			this->emit(Signal_ItemInserted, widget);
			return true;
		}
		return false;
	}
	return false;
}
bool BScrollWidget::removeWidget(BWidget* widget)
{
	if (!widget)
		return false;
	if (member.layout->remove(widget))
	{
		BHolder<BWidget> holder(widget);
		member.layout->remove(widget);
		this->emit(Signal_ItemRemoved, widget);
		this->fresh();
		return true;
	}
	return false;
}
bool BScrollWidget::removeWidget(int index)
{
	BWidget* widget = member.layout->widget(index);
	return removeWidget(widget);
}
bool BScrollWidget::clearWidgets()
{
	if (member.layout->count())
	{
		while (int count = member.layout->count())
		{
			BHolder<BWidget> widget = member.layout->widget(count - 1);
			member.layout->remove(widget);
			this->emit(Signal_ItemRemoved, widget);
		}
		this->fresh();
		return true;
	}
	return false;
}

int BScrollWidget::index(const BWidget* widget) const
{
	if (member.orientation == Orientation_Vertical)
	{
		BVBoxLayout* vlayout = member.layout.as<BVBoxLayout>();
		return vlayout->index(widget);
	}
	if (member.orientation == Orientation_Horizontal)
	{
		BHBoxLayout* hlayout = member.layout.as<BHBoxLayout>();
		return hlayout->index(widget);
	}
	return false;
}
int BScrollWidget::widgetCount() const
{
	return member.layout->count();
}
BWidget* BScrollWidget::widget(int index)
{
	return member.layout->widget(index);
}
const BWidget* BScrollWidget::widget(int index) const
{
	return member.layout->widget(index);
}

BWidget* BScrollWidget::widget(const BString& name)
{
	return member.layout->findWidget(name);
}
const BWidget* BScrollWidget::widget(const BString& name) const
{
	return member.layout->findWidget(name);
}

BWidget* BScrollWidget::widgetOfAsset(const BValue& value)
{
	for (int i = 0; i < member.layout->count(); i++)
	{
		BWidget* widget = member.layout->widget(i);
		if (!widget)
			continue;
		if (widget->asset() == value)
			return widget;
	}
	return 0;
}
const BWidget* BScrollWidget::widgetOfAsset(const BValue& value) const
{
	for (int i = 0; i < member.layout->count(); i++)
	{
		const BWidget* widget = member.layout->widget(i);
		if (!widget)
			continue;
		if (widget->asset() == value)
			return widget;
	}
	return 0;
}

bool BScrollWidget::setWidgetStretch(BWidget* widget, float stretch)
{
	if (member.layout->contain(widget))
	{
		if (BVBoxLayout* vlayout = member.layout.as<BVBoxLayout>())
		{
			int index = vlayout->index(widget);
			return vlayout->setStretch(index, stretch);
		}
		if (BHBoxLayout* hlayout = member.layout.as<BHBoxLayout>())
		{
			int index = hlayout->index(widget);
			return hlayout->setStretch(index, stretch);
		}
	}
	return false;
}
float BScrollWidget::widgetStretch(const BWidget* widget) const
{
	if (member.layout->contain(widget))
	{
		if (BVBoxLayout* vlayout = member.layout.as<BVBoxLayout>())
		{
			int index = vlayout->index(widget);
			return vlayout->stretch(index);
		}
		if (BHBoxLayout* hlayout = member.layout.as<BHBoxLayout>())
		{
			int index = hlayout->index(widget);
			return hlayout->stretch(index);
		}
	}
	return 0.0f;
}

BLayout* BScrollWidget::areaLayout()
{
	return member.layout;
}
const BLayout* BScrollWidget::areaLayout() const
{
	return member.layout;
}

void BScrollWidget::scrolling(Orientation orientation)
{
	if (BLayout* layout = member.layout)
	{
		BRect area = this->area();
		layout->setRect(area);
		layout->adjust();
		this->fresh();
	}
	BScrollArea::scrolling(orientation);
}

void BScrollWidget::resizeEvent(const BEvent& event)
{
	if (member.layout)
	{
		member.layout->dirty();
	}
	BScrollArea::resizeEvent(event);
}

void BScrollWidget::styleEvent(const BEvent& event)
{
	BScrollArea::styleEvent(event);
	const BStyle* style = event.value();

	const BValue& orientationValue = style->value(Value_Orientation);
	if (orientationValue.valid())
	{
		Orientation orientation = orientationValue;
		this->setOrientation(orientation);
	}
}
void BScrollWidget::freshEvent(const BEvent& event)
{
	if (BLayout* layout = member.layout)
	{
		BSize preferSize = layout->preferSize();
		if (area_member(this)->rawArea.size() != preferSize)
		{
			BRect area = area_member(this)->rawArea;
			area.setSize(preferSize);
			this->setArea(area);
		}
	}
	BScrollArea::freshEvent(event);
}
